/*****************************************************************************
*                     Organizacion de Datos - 75.06                          *
*                         Catedra Lic. Servetto                              *
*            Facultad de Ingenieria - Universidad de Buenos Aires            *
******************************************************************************/

#include "ParseadorComandos.h"
#include "AdministradorDeOperaciones.h"
#include "AdministradorMetadata.h"
#include "../Comun/Archivo.h"

#include <list>
#include <string>
#include <fstream>

using namespace Comun;

namespace CapaConsulta 
{
	

	Operacion* ParseadorComandos::ParsearActualizacion(list<string>* operacion) {
		
		
		Actualizacion* operacionActualizacion = new Actualizacion();
		map<string, AdministradorMetadata*> administradores = *(new map<string, AdministradorMetadata*>());
		
		/***************************************/
		/* UPDATE                              */
		/***************************************/
		
		string updateSupuesto = operacion->front();
		if (updateSupuesto != "UPDATE")
		{
			cerr << "La actualizacion en una clase espera el comando DELETE, se encontro " << updateSupuesto << "." << endl;
			throw new exception();
		}
		ParseadorComandos::SacarConComprobacion(operacion, "UPDATE");
		
		/***************************************/
		/* Clase                               */
		/***************************************/
		
		string claseSupuesto = operacion->front();
		AdministradorMetadata* administrador = new AdministradorMetadata(claseSupuesto);
		if (!administrador->ExisteClase())
		{
			cerr << "No se puede encontrar la clase '" << claseSupuesto << "' en el repositorio." << endl;
			throw new exception();
		}
		ParseadorComandos::SacarConComprobacion(operacion, "UPDATE");
		administradores.insert( *(new pair<string, AdministradorMetadata*>(claseSupuesto, administrador)) );
		operacionActualizacion->ClaseOperacion = administrador->ClaseMetadata;
		
		/***************************************/
		/* SET                                */
		/***************************************/
		
		string setSupuesto = operacion->front();
		if (setSupuesto != "SET")
		{
			cerr << "La actualizacion en una clase espera el comando SET despues de la clase, se encontro " << setSupuesto << "." << endl;
			throw new exception();
		}
		ParseadorComandos::SacarConComprobacion(operacion, "UPDATE");
		
		/***************************************/
		/* Atributo = Valor, Atributo = Valor  */
		/***************************************/
		
		string atributoSupuesto = operacion->front();
		//ParseadorComandos::SacarConComprobacion(operacion, "UPDATE");
		
		while(atributoSupuesto != "WHERE")
		{
			if (!administrador->EsAtributoDeLaClase(atributoSupuesto))
			{
				cerr << "El atributo  " << atributoSupuesto << " no pertenece a la clase" << claseSupuesto << "." << endl;
				throw new exception();
			}
			ParseadorComandos::SacarConComprobacion(operacion, "UPDATE");
			
			ClaveValor claveValorTemporal = (* new ClaveValor());
			claveValorTemporal.Clave = atributoSupuesto;
			
			/***************************************/
			/* =                                   */
			/***************************************/
			
			string igualSupuesto = operacion->front();
			if (igualSupuesto != "=")
			{
				cerr << "La actualizacion de atributos espera un = con el nuevo valor, en ves del = se encontro " << igualSupuesto << "." << endl;
				throw new exception();
			}
			ParseadorComandos::SacarConComprobacion(operacion, "UPDATE");
		
			/***************************************/
			/* Valor                               */
			/***************************************/
		
			string valorSupuesto = operacion->front();
			
			string valorLimpio;
			if (valorSupuesto[0] == '\'')
			{
				if (!ParseadorComandos::ValidarDatosEntreComillasSimples(valorSupuesto))
				{
					cerr << "Los datos deben estar entre comillas simples ''. Se encontro " << valorSupuesto << "." << endl;
					throw new exception();
				}
				valorLimpio = ParseadorComandos::EliminarComillasSimplesDeDatos(valorSupuesto);
			}
			else
			{
				valorLimpio = valorSupuesto;
			}
			
			
			if (!administrador->BuscarAtributoPorNombre(atributoSupuesto))
			{
				cerr << "No se encuentra el atributo " << atributoSupuesto << " en la clase " << claseSupuesto << "." << endl;
				throw new exception();
			}
			
			if (!administrador->ElValorDelAtributoEsCorrecto(atributoSupuesto, valorSupuesto))
			{
				cerr << "No se puede parsear correctamente el tipo del atributo " << atributoSupuesto << " en la condicion. El valor '" << valorSupuesto << "' no es correcto." << endl;
				throw new exception();
			}
			
			ParseadorComandos::SacarConComprobacion(operacion, "SELECT");
			
			claveValorTemporal.Valor = valorLimpio;
			
			operacionActualizacion->Valores->push_back(claveValorTemporal);
			
			string comaOWhereSupuesto = operacion->front();
			
			if (comaOWhereSupuesto != "," && comaOWhereSupuesto != "WHERE")
			{
				cerr << "La actualizacoin espera los pares clave = valor separados por comas y luego un WHERE, en lugar de eso se encontro " << comaOWhereSupuesto << "." << endl;
				throw new exception();
			}
			
			if (comaOWhereSupuesto == ",")
			{
				ParseadorComandos::SacarConComprobacion(operacion, "SELECT");
				atributoSupuesto = operacion->front();
				ParseadorComandos::SacarConComprobacion(operacion, "SELECT");
			}
			else if (comaOWhereSupuesto == "WHERE")
			{
				atributoSupuesto = comaOWhereSupuesto;
			}
			
		}
		
		/***************************************/
		/* WHERE                               */
		/***************************************/
		
		CondicionCompuesta* condicionCompuesta;
		condicionCompuesta = ParseadorComandos::ParsearWhere("UPDATE", operacion, administradores, false);
		operacionActualizacion->Condiciones = condicionCompuesta;
		
		if (!operacion->empty())
		{
			cerr << "Se econtraron " << operacion->size() << " cadena(s) no esperadas al final de la operacion UPDATE" << endl;
			throw new exception();
		}
		
		return operacionActualizacion;
	};
	
}
